<template>
  <div>
    <BBTable
      :data-source="groupedStageList"
      :show-header="true"
      :custom-header="true"
      :row-clickable="false"
    >
      <template #header>
        <tr>
          <BBTableHeaderCell compact class="w-1/12 pl-3 pr-2 whitespace-nowrap">
            {{ displayDeploymentMatchSelectorKey(label) }}
          </BBTableHeaderCell>

          <BBTableHeaderCell
            v-for="(xValue, i) in xAxisValueList"
            :key="xValue"
            :style="{ width: headerColumnWidth }"
            compact
            class="text-center py-2"
          >
            <NPopover placement="top" trigger="hover">
              <template #trigger>
                <span
                  class="px-1.5 py-1 relative rounded inline-flex items-center hover:bg-control-bg-hover cursor-pointer select-none"
                >
                  {{ xValue }}
                </span>
              </template>
              <div class="space-y-1">
                <div class="textlabel">
                  {{ $t("deployment-config.selectors") }}
                </div>
                <DeploymentStage
                  v-if="deployment.schedule"
                  :allow-edit="false"
                  :show-header="false"
                  :deployment="deployment.schedule.deployments[i]"
                  layout="compact"
                />
              </div>
            </NPopover>
          </BBTableHeaderCell>

          <BBTableHeaderCell v-if="hasRest" compact class="text-center py-2">
            <NPopover placement="top" trigger="hover">
              <template #trigger>
                <span
                  class="px-1.5 py-1 relative rounded inline-flex items-center hover:bg-control-bg-hover cursor-pointer select-none"
                >
                  {{ $t("deployment-config.wont-be-deployed") }}
                </span>
              </template>
              <div class="flex items-center text-sm max-w-[16rem]">
                {{ $t("deployment-config.wont-be-deployed-explanation") }}
              </div>
            </NPopover>
          </BBTableHeaderCell>
        </tr>
      </template>

      <template #body="{ rowData: matrix }">
        <BBTableCell
          :left-padding="4"
          class="pr-2 whitespace-nowrap"
          :class="{
            'text-control-placeholder': !matrix.labelValue,
          }"
        >
          <template v-if="matrix.labelValue">{{ matrix.labelValue }}</template>
          <template v-else>{{ $t("label.empty-label-value") }}</template>
        </BBTableCell>
        <BBTableCell v-for="(dbList, i) in matrix.stages" :key="i">
          <div
            v-if="databaseList.length > 0"
            class="flex flex-col items-start w-max mx-auto space-y-1"
          >
            <DatabaseMatrixItem
              v-for="db in dbList"
              :key="db.id"
              :database="db"
            />
          </div>
          <div v-if="dbList.length === 0" class="text-center">-</div>
        </BBTableCell>

        <BBTableCell v-if="hasRest">
          <div
            v-if="databaseList.length > 0"
            class="flex flex-col items-start w-max mx-auto space-y-1"
          >
            <DatabaseMatrixItem
              v-for="db in matrix.rest"
              :key="db.id"
              :database="db"
            />
          </div>
          <div v-if="matrix.rest.length === 0" class="text-center">-</div>
        </BBTableCell>
      </template>
    </BBTable>
  </div>
</template>

<script lang="ts" setup>
import { groupBy } from "lodash-es";
import { NPopover } from "naive-ui";
import { computed } from "vue";
import { BBTable, BBTableCell, BBTableHeaderCell } from "@/bbkit";
import type { ComposedDatabase } from "@/types";
import type { Environment } from "@/types/proto/v1/environment_service";
import type { DeploymentConfig } from "@/types/proto/v1/project_service";
import {
  getLabelValuesFromDatabaseV1List,
  getPipelineFromDeploymentScheduleV1,
  displayDeploymentMatchSelectorKey,
  getSemanticLabelValue,
} from "@/utils";
import { DeploymentStage } from "../DeploymentConfigTool";
import DatabaseMatrixItem from "./DatabaseMatrixItem.vue";

const props = withDefaults(
  defineProps<{
    databaseList: ComposedDatabase[];
    label: string;
    environmentList: Environment[];
    deployment: DeploymentConfig;
    bordered?: boolean;
    showRest?: boolean;
  }>(),
  {
    bordered: true,
    showRest: true,
  }
);

const yAxisValueList = computed(() => {
  return getLabelValuesFromDatabaseV1List(
    props.label,
    props.databaseList,
    true /* withEmptyValue */
  );
});

const xAxisValueList = computed(() => {
  // x-axis is generated by deployment stages
  const deployments = props.deployment.schedule?.deployments ?? [];
  return deployments.map((dep) => dep.title);
});

const databaseGroupList = computed(() => {
  const key = props.label;
  const dict = groupBy(props.databaseList, (db) =>
    getSemanticLabelValue(db, key)
  );
  const rows = yAxisValueList.value.map((labelValue) => {
    const databaseList = dict[labelValue] || [];
    return {
      labelValue,
      databaseList,
    };
  });

  if (rows.length > 0 && rows[rows.length - 1].databaseList.length === 0) {
    // ignore "<empty value>" row if no databases
    rows.pop();
  }

  return rows;
});

const groupedStageList = computed(() => {
  return databaseGroupList.value.map(({ labelValue, databaseList }) => {
    const stages = getPipelineFromDeploymentScheduleV1(
      databaseList,
      props.deployment.schedule
    );
    const affectedIds = stages.flatMap((dbs) => dbs.map((db) => db.uid));
    const dict = new Set(affectedIds);
    const rest = props.showRest
      ? databaseList.filter((db) => !dict.has(db.uid))
      : [];

    return {
      labelValue,
      stages,
      rest,
    };
  });
});

const hasRest = computed(() => {
  return groupedStageList.value.some((group) => group.rest.length > 0);
});

const headerColumnWidth = computed(() => {
  let base = xAxisValueList.value.length;
  if (hasRest.value) base += 1;
  return `${(100 - 1 / 12) / base - 1}%`;
});
</script>
